package cn.yeziji.forum.utils;

import cn.yeziji.forum.common.BasicEnum;
import lombok.SneakyThrows;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Objects;
import java.util.function.Predicate;

/**
 * 基础枚举超类
 *
 * @author hwy
 * @since 2023/07/13 14:23
 **/
public class BasicEnumAnalyzeUtils implements BasicEnum {
  Class<? extends Enum> clazz;

  Method getCodeMethod;

  Method getDescMethod;

  @SneakyThrows
  public static BasicEnumAnalyzeUtils getInstance(Class<? extends Enum> clazz) {
    BasicEnumAnalyzeUtils basicEnumAnalyzeUtils = new BasicEnumAnalyzeUtils();
    basicEnumAnalyzeUtils.clazz = clazz;
    basicEnumAnalyzeUtils.getCodeMethod = clazz.getMethod("getCode");
    basicEnumAnalyzeUtils.getDescMethod = clazz.getMethod("getDesc");
    return basicEnumAnalyzeUtils;
  }

  @Override
  public Enum getByCode(final int code) {
    return this.<Integer>findEnum(this.getCodeMethod, (invoke) -> invoke == code);
  }

  @Override
  public Enum getByDesc(final String desc) {
    return this.<String>findEnum(this.getDescMethod, (invoke) -> Objects.equals(invoke, desc));
  }

  @Override
  public Enum getByValue(Object value) {
    return this.findEnum(this.getDescMethod, (invoke) -> Objects.equals(invoke, value));
  }

  @Override
  public boolean hasCode(final int code) {
    return !Objects.isNull(getByCode(code));
  }

  @Override
  public boolean hasDesc(final String desc) {
    return !Objects.isNull(getByDesc(desc));
  }

  @Override
  public boolean hasValue(Object value) {
    return !Objects.isNull(getByValue(value));
  }

  @SneakyThrows({InvocationTargetException.class, IllegalAccessException.class})
  private <T> Enum findEnum(final Method method, final Predicate<T> predicate) {
    Enum[] enumConstants = clazz.getEnumConstants();
    for (Enum enumConstant : enumConstants) {
      T invoke = (T) method.invoke(enumConstant);
      if (predicate.test(invoke)) {
        return enumConstant;
      }
    }
    return null;
  }
}
